package com.example.playlet.utils;

import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * 提供获取当前系统时间、日期及日期推算的工具方法。
 */
public class GetFormat {


    /**
     * 判断给定日期是否在当前年份的有效期内
     * 有效日期被定义为当前年的1月1日到12月31日
     *
     * @param nowTime 给定的日期对象
     * @return 如果给定日期在有效期内，则返回true；否则返回false
     */
    public static boolean isEctiveDate(Date nowTime) {
        // 获取当前年份
        int currentYear = LocalDate.now().getYear();
        // 构造当前年的第一天（1月1日）
        LocalDateTime firstDayOfYear = LocalDateTime.of(currentYear, 1, 1, 0, 0, 0);
        Date startTime = Date.from(firstDayOfYear.atZone(ZoneId.systemDefault()).toInstant());
        // 构造当前年的最后一天（12月31日）
        LocalDateTime lastDayOfYear = LocalDateTime.of(currentYear, 12, 31, 23, 59, 59);
        Date endTime = Date.from(lastDayOfYear.atZone(ZoneId.systemDefault()).toInstant());
        // 检查给定日期是否为当前年的第一天或最后一天
        if (nowTime.getTime() == startTime.getTime() || nowTime.getTime() == endTime.getTime()) {
            return true;
        }
        // 检查给定日期是否在当前年的第一天和最后一天之间
        return nowTime.after(startTime) && nowTime.before(endTime);
    }


    /**
     * 判断给定日期是否在当前年份的特定时间范围内
     * 特定时间范围是当前年份的1月1日0点到12月31日23点59分
     * 此方法用于确定一个日期是否落在一个特定的年度时间区间内，主要用于年度数据统计或分析
     *
     * @param dt_2 待检查的日期，用于判断是否在指定的时间范围内
     * @return 如果给定日期在当前年份的指定时间范围内，则返回true；否则返回false
     */
    public static boolean isBetweenTime(Date dt_2) {
        // 获取当前系统时间
        Calendar cal = Calendar.getInstance();
        // 设置日历对象的时间为传入的待检查时间
        cal.setTime(dt_2);
        // 构建待检查的本地日期时间对象
        LocalDateTime timeToCheck = LocalDateTime.of(cal.get(Calendar.YEAR), (cal.get(Calendar.MONTH) + 1), cal.get(Calendar.DAY_OF_MONTH), cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE), cal.get(Calendar.SECOND));

        // 构建当前年份1月1日0点的本地日期时间对象，作为时间范围的开始时间
        LocalDateTime startTime = LocalDateTime.of(Year.now().getValue(), 1, 1, 0, 0, 0);

        // 构建当前年份12月31日23点59分的本地日期时间对象，作为时间范围的结束时间
        LocalDateTime endTime = LocalDateTime.of(Year.now().getValue(), 12, 31, 23, 59, 59);

        // 判断待检查时间是否在指定的时间范围内
        return timeToCheck.isAfter(startTime) && timeToCheck.isBefore(endTime);
    }


    /**
     * 判断给定日期是否在当前年份的范围内
     * 即判断日期是否在当前年份的1月1日到12月31日之间
     * 此方法用于确定一个日期是否属于当前年份的任何一个时间点
     *
     * @param dt_2 需要判断的日期
     * @return 如果给定日期在当前年份范围内，则返回true；否则返回false
     */
    public static boolean isBetweenDate(Date dt_2) {
        // 获取当前日期的年份
        Calendar dar = Calendar.getInstance();
        // 设置日历为输入的日期
        dar.setTime(dt_2);
        // 转换输入日期为LocalDate对象，以便进行日期比较
        LocalDate targetDate = LocalDate.of(dar.get(Calendar.YEAR), (dar.get(Calendar.MONTH) + 1), dar.get(Calendar.DAY_OF_MONTH)); // 要判断的日期
        // 获取当前年份的起始日期（1月1日）
        LocalDate startDate = LocalDate.of(Year.now().getValue(), 1, 1); // 起始日期
        // 获取当前年份的结束日期（12月31日）
        LocalDate endDate = LocalDate.of(Year.now().getValue(), 12, 31); // 结束日期
        // 检查日期是否在起始日期之后并且结束日期之前
        return !targetDate.isBefore(startDate) && !targetDate.isAfter(endDate);
    }

    /**
     * 获取当前年份的字符串表示
     * <p>
     * 此方法使用SimpleDateFormat类来格式化当前日期，以便仅提取年份部分
     * 它在需要当前年份信息的场景中很有用
     *
     * @return 当前年份的字符串表示，格式为"yyyy"
     */
    public static String getYear() {
        // 创建一个SimpleDateFormat实例，用于格式化日期为年份格式
        SimpleDateFormat simp = new SimpleDateFormat("yyyy");
        // 使用当前日期实例，格式化为年份字符串并返回
        return simp.format(new Date());
    }


    /**
     * 获取当前月份
     * <p>
     * 此方法使用SimpleDateFormat类来格式化当前日期，仅返回月份部分
     * 选择使用"MM"作为格式化模式，确保返回的月份是两位数的字符串形式，例如："01"到"12"
     *
     * @return 当前的月份，以两位数的字符串形式返回
     */
    public static String getMonth() {
        // 创建一个SimpleDateFormat实例，用于格式化日期为两位数的月份
        SimpleDateFormat simp = new SimpleDateFormat("MM");
        // 使用当前日期实例化Date对象，并用SimpleDateFormat实例格式化该日期，返回月份字符串
        return simp.format(new Date());
    }

    /**
     * 获取当前日期的天数
     * 此方法使用SimpleDateFormat类来格式化当前日期，仅返回日期的天数部分
     * 选择"dd"作为日期格式，以获取两位数的天数
     *
     * @return 当前日期的天数，以字符串形式返回
     */
    public static String getDays() {
        // 创建一个SimpleDateFormat实例，用于格式化日期
        SimpleDateFormat simp = new SimpleDateFormat("dd");
        // 使用当前日期实例化Date对象，并用SimpleDateFormat实例格式化该日期，返回天数字符串
        return simp.format(new Date());
    }


    /**
     * 获取当前时间的字符串表示
     * <p>
     * 该方法使用SimpleDateFormat类来格式化当前时间，格式为小时:分钟:秒（HH:mm:ss）
     * 主要用于需要显示当前时间的场景，例如日志记录、时间戳等
     *
     * @return 当前时间的字符串表示，格式为HH:mm:ss
     */
    public static String getTime() {
        // 创建SimpleDateFormat实例，指定时间格式为HH:mm:ss
        SimpleDateFormat simp = new SimpleDateFormat("HH:mm:ss");
        // 使用当前日期时间实例化Date对象，并格式化为字符串返回
        return simp.format(new Date());
    }

    /**
     * 获取当前时间的小时和分钟
     * <p>
     * 此方法使用SimpleDateFormat类来格式化当前时间，仅返回小时和分钟部分
     * 选择使用"HH:mm"作为格式字符串，其中"HH"代表24小时制小时数，"mm"代表分钟
     *
     * @return 当前时间的小时和分钟，格式为HH:mm
     */
    public static String getMinute() {
        SimpleDateFormat simp = new SimpleDateFormat("HH:mm");
        return simp.format(new Date());
    }


    /**
     * 获取当前日期的年月字符串表示
     * 此方法使用SimpleDateFormat类来格式化当前日期它创建了一个SimpleDateFormat实例，
     * 指定格式为"yyyyMM"，然后使用这个实例将当前日期格式化为一个字符串该字符串表示了当前的年月，
     * 例如"202304"表示2023年4月这种方法常用于需要以紧凑格式表示日期的场景，比如文件名、数据库索引等
     *
     * @return 当前日期的年月字符串，格式为"yyyyMM"
     */
    public static String getDate1() {
        // 创建一个SimpleDateFormat实例，指定日期格式为"yyyyMM"
        SimpleDateFormat simp = new SimpleDateFormat("yyyyMM");
        // 使用SimpleDateFormat实例格式化当前日期，并返回格式化后的日期字符串
        return simp.format(new Date());
    }

    /**
     * 获取当前日期的年月信息
     * 此方法使用SimpleDateFormat类来格式化当前日期，仅显示年份和月份
     * 选择"yyyy/MM"格式是为了在不同的情境下清晰地展示日期信息
     *
     * @return 当前日期的年月信息，格式为"yyyy/MM"
     */
    public static String getDate2() {
        // 创建SimpleDateFormat实例，指定输出格式为"yyyy/MM"
        SimpleDateFormat simp = new SimpleDateFormat("yyyy/MM");
        // 使用当前日期实例格式化日期，并返回格式化后的日期字符串
        return simp.format(new Date());
    }


    /**
     * 获取当前日期的年月格式字符串
     * <p>
     * 此方法用于获取当前系统日期，并以"yyyy-MM"的格式返回
     * 主要用途是在需要按月统计或展示信息时，作为日期标识或筛选条件
     *
     * @return 当前日期的年月格式字符串，例如"2023-10"
     */
    public static String getDate3() {
        // 创建SimpleDateFormat实例，用于日期格式化
        SimpleDateFormat simp = new SimpleDateFormat("yyyy-MM");
        // 使用当前日期实例格式化日期，并返回格式化后的日期字符串
        return simp.format(new Date());
    }


    /**
     * 获取当前日期的字符串表示，格式为yyyyMMdd
     * <p>
     * 选择这种格式是因为它常用于需要日期作为唯一标识的场景，如文件名、版本号等
     * 这种格式的好处是按日期自然排序时，字符串也会按照日期顺序排列
     *
     * @return 当前日期的字符串表示，格式为yyyyMMdd
     */
    public static String getDate4() {
        // 创建一个SimpleDateFormat实例，用于格式化日期
        SimpleDateFormat simp = new SimpleDateFormat("yyyyMMdd");
        // 使用当前日期时间进行格式化，并返回结果字符串
        return simp.format(new Date());
    }


    /**
     * 获取当前日期并以"yyyy-MM-dd"格式返回
     * 该方法使用SimpleDateFormat类来格式化当前日期（new Date()），
     * 并以字符串形式返回日期，日期格式为"年-月-日"。
     *
     * @return 当前日期的字符串表示，格式为"yyyy-MM-dd"
     */
    public static String getDate5() {
        // 创建SimpleDateFormat实例，指定日期格式为"yyyy-MM-dd"
        SimpleDateFormat simp = new SimpleDateFormat("yyyy-MM-dd");
        // 使用SimpleDateFormat实例格式化当前日期，并返回格式化后的日期字符串
        return simp.format(new Date());
    }


    /**
     * 获取当前日期并以"yyyy/MM/dd"格式返回
     * 该方法使用SimpleDateFormat类来格式化当前日期（new Date()），
     * 并以字符串形式返回，适用于需要日期字符串的场景
     *
     * @return 当前日期的字符串表示，格式为"yyyy/MM/dd"
     */
    public static String getDate6() {
        // 创建SimpleDateFormat实例，指定日期格式为"yyyy/MM/dd"
        SimpleDateFormat simp = new SimpleDateFormat("yyyy/MM/dd");
        // 使用SimpleDateFormat实例格式化当前日期，并返回格式化后的日期字符串
        return simp.format(new Date());
    }


    /**
     * 获取当前日期和时间的字符串表示
     * 该方法使用"yyyy-MM-dd HH:mm"格式来格式化当前日期和时间
     * 主要用于需要以"年-月-日 时:分"格式显示当前日期和时间的场景
     *
     * @return 当前日期和时间的字符串表示，格式为"yyyy-MM-dd HH:mm"
     */
    public static String getDate7() {
        // 创建一个SimpleDateFormat实例，用于格式化日期和时间
        SimpleDateFormat simp = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        // 使用SimpleDateFormat实例格式化当前日期和时间，并返回格式化后的字符串
        return simp.format(new Date());
    }


    /**
     * 获取当前日期和时间的字符串表示
     * 格式为yyyyMMddHHmmss
     *
     * @return 当前日期和时间的字符串表示
     */
    public static String getDate8() {
        // 创建一个SimpleDateFormat实例，用于格式化日期和时间
        SimpleDateFormat simp = new SimpleDateFormat("yyyyMMddHHmmss");
        // 将当前日期和时间格式化为指定格式，并返回结果字符串
        return simp.format(new Date());
    }


    /**
     * 获取当前日期和时间的字符串表示，格式为yyyyMMddHHmmssSSS
     * 此方法用于获取当前日期和时间的精确到毫秒的字符串表示，主要用途包括：
     * 1. 生成唯一标识符，如订单号、交易号等，确保在高并发情况下也能保持唯一性
     * 2. 数据库记录的时间戳字段赋值，确保时间数据的精确性和一致性
     * 选择这种时间格式的原因是它不仅包含了年月日时分秒，还包含了毫秒信息，能够提供更为精确的时间点标识
     * 使用SimpleDateFormat类来格式化当前时间（Date对象），确保输出符合预期格式
     *
     * @return 当前日期和时间的字符串表示，格式为yyyyMMddHHmmssSSS
     */
    public static String getDate9() {
        // 创建SimpleDateFormat实例，指定输出格式为"yyyyMMddHHmmssSSS"
        SimpleDateFormat simp = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        // 使用当前日期和时间格式化为字符串并返回
        return simp.format(new Date());
    }


    /**
     * 获取当前日期和时间的字符串表示，格式为"yyyy-MM-dd HH:mm:ss.SSS"
     * 此方法用于获取当前系统日期和时间，并以特定格式返回
     * 使用SimpleDateFormat类进行日期时间格式的定义和格式化
     *
     * @return 当前日期和时间的字符串表示，格式为"yyyy-MM-dd HH:mm:ss.SSS"
     */
    public static String getDate10() {
        // 创建SimpleDateFormat实例，定义日期时间格式
        SimpleDateFormat simp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        // 使用当前日期时间格式化并返回日期时间字符串
        return simp.format(new Date());
    }


    /**
     * 获取当前时间的字符串表示
     * 该方法使用SimpleDateFormat类来格式化当前时间（精确到秒），并以字符串形式返回
     * 主要用于需要显示当前时间的场景，如日志记录、时间戳生成等
     *
     * @return 当前时间的字符串表示，格式为"yyyy-MM-dd HH:mm:ss"
     */
    public static String getHours() {
        // 创建SimpleDateFormat实例，指定输出时间格式
        SimpleDateFormat simp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // 使用当前日期时间初始化Date对象
        Date now = new Date();
        // 格式化当前时间并返回
        return simp.format(now);
    }


    /**
     * 根据当前日期计算并返回未来或过去指定年数的日期
     * 该方法用于获取从当前日期起，向前或向后推算指定年数的日期字符串
     * 主要用于需要根据当前年份进行日期推算的场景
     *
     * @param year 一个整数，表示需要推算的年数正值表示未来年数，负值表示过去年数
     * @return 返回一个字符串，表示推算年后的时间，格式为"yyyy-MM-dd"
     */
    public static String getPushYear(Integer year) {
        // 创建一个Calendar实例，用于日期操作
        Calendar calendar = Calendar.getInstance();
        // 设置日历的时间为当前日期
        calendar.setTime(new Date());
        // 添加指定年数到当前年份，正值向后推算，负值向前推算
        calendar.add(Calendar.YEAR, year);
        // 创建一个SimpleDateFormat实例，用于格式化日期
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        // 返回格式化后的日期字符串
        return sdf.format(calendar.getTime());
    }


    /**
     * 根据当前日期计算未来或过去指定月数的日期
     * 该方法用于获取从当前日期起，向前或向后推算指定月份的日期字符串
     * 主要用于需要根据当前年份进行日期推算的场景
     *
     * @param month 需要添加到当前月份的月数，正数表示未来月份，负数表示过去月份
     * @return 计算后的日期字符串，格式为"yyyy-MM-dd"
     */
    public static String getPushMonth(Integer month) {
        // 获取当前系统日期
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        // 计算月份
        calendar.add(Calendar.MONTH, month);
        // 创建日期格式化对象，用于将日期对象转换为字符串
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        // 返回计算后的日期字符串
        return sdf.format(calendar.getTime());
    }


    /**
     * 计算相对于当前日期的未来某一天的日期
     * 该方法用于获取从当前日期起，向前或向后推算指定天数的日期字符串
     * 主要用于需要根据当前年份进行日期推算的场景
     *
     * @param day 相对于当前日期的天数，正数表示未来，负数表示过去
     * @return 未来某一天的日期，格式为"yyyy-MM-dd"
     */
    public static String getPushDay(Integer day) {
        // 获取当前系统日期和时间
        Calendar calendar = Calendar.getInstance();
        // 设置日历的时间为当前时间
        calendar.setTime(new Date());
        // 在当前日期上增加指定天数，正数表示未来，负数表示过去
        calendar.add(Calendar.DATE, day);
        // 获取计算后的未来日期
        Date futureDate = calendar.getTime();
        // 创建日期格式化对象，用于将日期对象转换为指定格式的日期字符串
        SimpleDateFormat simp = new SimpleDateFormat("yyyy-MM-dd");
        // 将未来日期格式化为字符串并返回
        return simp.format(futureDate);
    }


    /**
     * 根据当前日期计算并返回未来某个月份和日期对应的日期字符串
     *
     * @param month 未来月份的偏移量，例如-1表示一个月前，1表示一个月后
     * @param day   未来日期的偏移量，例如-1表示一天前，1表示一天后
     * @return 返回计算后的日期字符串，格式为"yyyy-MM-dd"
     */
    public static String getPushBack(Integer month, Integer day) {
        // 获取当前系统日期
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        // 在当前日期上增加指定的月份偏移量
        calendar.add(Calendar.MONTH, month);
        // 在当前日期上增加指定的日期偏移量，正数表示未来，负数表示过去
        calendar.add(Calendar.DATE, day);
        // 创建日期格式化对象，用于将日期对象转换为字符串
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        // 返回格式化后的日期字符串
        return sdf.format(calendar.getTime());
    }


    /**
     * 根据当前日期计算并返回增加指定年、月、日后的新日期
     *
     * @param year  需要增加的年数，可为负数
     * @param month 需要增加的月数，可为负数
     * @param day   需要增加的天数，可为负数
     * @return 返回格式化后的日期字符串
     */
    public static String getPush(Integer year, Integer month, Integer day) {
        // 创建一个Calendar对象，用于日期计算
        Calendar calendar = Calendar.getInstance();
        // 设置日历时间为当前日期
        calendar.setTime(new Date());
        // 在当前年份上增加指定的年数，正数表示未来，负数表示过去
        calendar.add(Calendar.YEAR, year);
        // 在当前月份上增加指定的月数，正数表示未来，负数表示过去
        calendar.add(Calendar.MONTH, month);
        // 在当前日期上增加指定的天数，正数表示未来，负数表示过去
        calendar.add(Calendar.DATE, day);
        // 创建一个SimpleDateFormat对象，用于日期格式化
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        // 返回格式化后的日期字符串
        return sdf.format(calendar.getTime());
    }

    /**
     * 获取两个日期之间的所有星期六和星期日
     * 此方法首先解析输入的日期字符串，然后遍历两个日期之间的所有日期，
     * 找出所有的周末（星期六和星期日），并打印出来
     *
     * @param startTime 开始日期字符串，格式为"yyyy-MM-dd"
     * @param endTime   结束日期字符串，格式为"yyyy-MM-dd"
     * @return 返回日期集合
     */
    public static List<LocalDate> getWeek(String startTime, String endTime) {
        // 创建日期格式化器
        DateTimeFormatter simp = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        // 解析输入的开始日期和结束日期
        LocalDate startDate = LocalDate.parse(startTime, simp);
        LocalDate endDate = LocalDate.parse(endTime, simp);
        // 计算两个日期之间的所有星期六和星期日
        List<LocalDate> weekendDays = new ArrayList<>();
        for (LocalDate date = startDate; !date.isAfter(endDate); date = date.plusDays(1)) {
            // 检查当前日期是否为星期六或星期日
            if (date.getDayOfWeek() == DayOfWeek.SATURDAY || date.getDayOfWeek() == DayOfWeek.SUNDAY) {
                weekendDays.add(date);
            }
        }
//        // 打印结果
//        System.out.println("周六和周日 between " + startDate + " and " + endDate + ":");
//        for (LocalDate weekendDay : weekendDays) {
//            System.out.println(weekendDay.toString());
//        }
        return weekendDays;
    }

}